/**
 * ============万年历服务类开始===========
 * 万年历服务 - 提供农历、节气、生肖等计算功能
 * Lunar Calendar Service - Provides lunar calendar, solar terms, zodiac calculations
 * 
 * 功能说明：
 * - 基于 lunar-javascript 库实现万年历功能
 * - 提供公历转农历、节气计算、宜忌查询等功能
 * - 支持生肖运势、黄道吉日等传统文化功能
 * 
 * 依赖库说明：
 * - lunar-javascript: 专业的农历计算库，支持公历农历转换、节气计算等
 * - 使用方法：Solar.fromYmd(年, 月, 日) 创建公历对象，然后调用 getLunar() 获取农历信息
 * - 注意事项：日期参数必须为数字类型，字符串需要先转换为数字
 * 
 * 为什么选择 lunar-javascript 库：
 * 1. 算法精确：基于天文算法，计算结果准确可靠
 * 2. 功能全面：支持公历农历转换、节气、八字、宜忌等全套功能
 * 3. 性能优秀：纯JavaScript实现，无需外部依赖
 * 4. 维护活跃：持续更新，支持最新的农历算法
 */

// 导入农历计算库 - Import lunar calendar library
import { Lunar, Solar, HolidayUtil } from "lunar-javascript";

/**
 * 万年历服务类 - Lunar Calendar Service Class
 * 提供完整的万年历计算功能
 */
class LunarService {
  /**
   * ============获取万年历信息核心方法开始===========
   * 获取指定日期的完整万年历信息
   * Get complete lunar calendar information for specified date
   * 
   * @param {string} date - 日期字符串，格式：YYYY-MM-DD，例如："2024-01-15"
   * @returns {object} 万年历信息对象，包含公历、农历、八字、宜忌等完整信息
   * @throws {Error} 当日期格式错误或计算失败时抛出异常
   * 
   * 功能说明：
   * - 这是万年历服务的核心方法，所有其他方法都基于此方法
   * - 使用 lunar-javascript 库进行精确的农历计算
   * - 返回的数据结构包含了传统万年历的所有信息
   * 
   * 使用示例：
   * const info = lunarService.getCalendarInfo("2024-01-15");
   * console.log(info.lunar.yearInChinese); // 输出：甲辰年
   * 
   * 返回数据结构：
   * {
   *   solar: { year, month, day, weekDay, weekDayName, ... },      // 公历信息
   *   lunar: { year, month, day, yearInChinese, yearInGanZhi, ... }, // 农历信息
   *   baZi: { year, month, day, time },                            // 八字信息
   *   yiJi: { yi, ji, pengZu, chong, sha, ... },                  // 宜忌信息
   *   xingXiu: { xiu, zheng, animal, gong, shou },                // 星宿信息
   *   jieQi: string,                                              // 节气信息
   *   festivals: array                                            // 节日信息
   * }
   * 
   * 为什么需要这么详细的信息：
   * 1. solar: 公历信息是基础，用于日常显示和计算
   * 2. lunar: 农历信息是核心，传统文化的基础
   * 3. baZi: 八字用于运势计算和命理分析
   * 4. yiJi: 宜忌指导日常生活和重要决策
   * 5. xingXiu: 星宿信息用于更精确的吉凶判断
   * 6. jieQi: 节气反映自然规律和季节变化
   * 7. festivals: 节日信息丰富文化内涵
   */
  getCalendarInfo(date) {
    try {
      // 第一步：解析日期字符串并创建公历对象 - Step 1: Parse date string and create solar object
      // 为什么要分割字符串：date参数是"YYYY-MM-DD"格式，需要提取年月日数字
      // 为什么使用parseInt：lunar-javascript库要求数字类型参数，字符串会导致计算错误
      const [yearStr, monthStr, dayStr] = date.split('-');
      const year = parseInt(yearStr, 10);    // 10表示十进制，避免八进制解析错误
      const month = parseInt(monthStr, 10);  // 月份：1-12
      const day = parseInt(dayStr, 10);      // 日期：1-31
      
      // 第二步：验证日期有效性 - Step 2: Validate date validity
      // 为什么需要验证：防止无效日期导致计算错误或程序崩溃
      if (isNaN(year) || isNaN(month) || isNaN(day)) {
        throw new Error(`日期格式错误: ${date}，正确格式应为 YYYY-MM-DD`);
      }
      
      // 创建公历对象 - Solar 类是 lunar-javascript 库的核心类
      const solar = Solar.fromYmd(year, month, day);
      
      // 第二步：获取对应的农历对象
      // getLunar() 方法将公历转换为农历，包含所有农历相关信息
      const lunar = solar.getLunar();

      // 第三步：构建完整的万年历信息对象
      return {
        // 公历信息 Solar calendar info
        solar: {
          year: solar.getYear(),                    // 公历年份
          month: solar.getMonth(),                  // 公历月份
          day: solar.getDay(),                      // 公历日期
          weekDay: solar.getWeek(),                 // 星期几（数字）
          weekDayName: solar.getWeekInChinese(),    // 星期几（中文）
          yearInChinese: solar.getYear() + "年",    // 年份中文表示
          monthInChinese: solar.getMonth() + "月",  // 月份中文表示
          dayInChinese: solar.getDay() + "日",      // 日期中文表示
        },

        // 农历信息 Lunar calendar info
        lunar: {
          year: lunar.getYear(),                    // 农历年份
          month: lunar.getMonth(),                  // 农历月份
          day: lunar.getDay(),                      // 农历日期
          yearInChinese: lunar.getYearInChinese(),  // 农历年份中文（如：甲辰年）
          yearInGanZhi: lunar.getYearInGanZhi(),    // 年份干支
          monthInChinese: lunar.getMonthInChinese(), // 农历月份中文（如：正月）
          dayInChinese: lunar.getDayInChinese(),    // 农历日期中文（如：初一）
          monthInGanZhi: lunar.getMonthInGanZhi(),  // 月份干支
          dayInGanZhi: lunar.getDayInGanZhi(),      // 日期干支
          timeInGanZhi: lunar.getTimeZhi() + "时",  // 时辰干支

          // 生肖信息 Zodiac info - 基于农历年、月、日、时计算
          yearShengXiao: lunar.getYearShengXiao(),  // 年生肖
          monthShengXiao: lunar.getMonthShengXiao(), // 月生肖
          dayShengXiao: lunar.getDayShengXiao(),    // 日生肖
          timeShengXiao: lunar.getTimeShengXiao(),  // 时生肖

          // 节气信息 Solar terms - 二十四节气相关
          jieQi: lunar.getJieQi(),                  // 当前节气
          nextJieQi: lunar.getNextJieQi(),          // 下一个节气

          // 节日信息 Festivals - 传统节日和现代节日
          festivals: lunar.getFestivals(),          // 农历节日
          otherFestivals: lunar.getOtherFestivals(), // 其他节日
        },

        // 八字信息 BaZi (Eight Characters) - 用于命理分析
        baZi: {
          year: lunar.getYearInGanZhi(),    // 年柱
          month: lunar.getMonthInGanZhi(),  // 月柱
          day: lunar.getDayInGanZhi(),      // 日柱
          time: lunar.getTimeInGanZhi(),    // 时柱
        },

        // 宜忌信息 Suitable and taboo activities - 黄历核心功能
        yiJi: {
          yi: lunar.getDayYi(),                                    // 宜做的事情
          ji: lunar.getDayJi(),                                    // 忌做的事情
          pengZu: lunar.getPengZuGan() + " " + lunar.getPengZuZhi(), // 彭祖百忌
          chong: lunar.getDayChong(),                              // 冲煞
          sha: lunar.getDaySha(),                                  // 煞向
          wuxing: this._getDayWuXing(lunar),                       // 五行属性
          nayin: lunar.getDayNaYin(),                              // 纳音五行

          // 时辰宜忌 Hourly suitable/taboo - 十二时辰的宜忌
          timeYiJi: this.getTimeYiJi(lunar),
        },

        // 星宿信息 Constellation info - 二十八宿相关
        xingXiu: {
          xiu: lunar.getXiu(),      // 二十八宿
          zheng: lunar.getZheng(),  // 正
          animal: lunar.getAnimal(), // 动物
          gong: lunar.getGong(),    // 宫
          shou: lunar.getShou(),    // 兽
        },

        // 九星信息 Nine Stars - 九宫飞星
        jiuXing: this._getJiuXing(lunar),

        // 胎神信息 Fetal God - 胎神占方
        taiShen: this._getTaiShen(lunar),
      };
    } catch (error) {
      // 异常处理：记录错误信息并重新抛出
      console.error(`获取万年历信息失败 - 日期: ${date}, 错误: ${error.message}`);
      throw new Error(`获取万年历信息失败: ${error.message}`);
    }
  }

  /**
   * 获取时辰宜忌信息
   * Get hourly suitable/taboo information
   * 
   * @param {Lunar} lunar - 农历对象，由 lunar-javascript 库创建
   * @returns {Array} 时辰宜忌数组，包含十二时辰的详细宜忌信息
   * 
   * 功能说明：
   * - 计算十二时辰（子丑寅卯辰巳午未申酉戌亥）的宜忌
   * - 每个时辰对应2小时，从子时（23:00-01:00）开始
   * - 基于农历日期和时辰干支计算宜忌事项
   * 
   * 使用示例：
   * const timeYiJi = this.getTimeYiJi(lunar);
   * console.log(timeYiJi[0]); // 子时的宜忌信息
   */
  getTimeYiJi(lunar) {
    const timeYiJi = [];
    // 十二时辰对应表
    const times = ["子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"];
    
    // 时辰对应的时间范围
    const timeRanges = [
      "23:00-01:00", "01:00-03:00", "03:00-05:00", "05:00-07:00",
      "07:00-09:00", "09:00-11:00", "11:00-13:00", "13:00-15:00", 
      "15:00-17:00", "17:00-19:00", "19:00-21:00", "21:00-23:00"
    ];

    for (let i = 0; i < times.length; i++) {
      // 基于农历信息计算每个时辰的宜忌
      const timeGanZhi = this._getTimeGanZhi(lunar, i);
      const timeYiJiInfo = this._calculateTimeYiJi(lunar, times[i]);
      
      timeYiJi.push({
        time: times[i],                    // 时辰名称
        timeRange: timeRanges[i],          // 时间范围
        ganZhi: timeGanZhi,                // 时辰干支
        yi: timeYiJiInfo.yi,               // 宜做事项
        ji: timeYiJiInfo.ji,               // 忌做事项
        chong: timeYiJiInfo.chong,         // 时辰冲煞
      });
    }

    return timeYiJi;
  }

  /**
   * 获取指定月份的黄道吉日
   * Get auspicious days for specified month
   * 
   * @param {number} year - 年份，例如：2024
   * @param {number} month - 月份，例如：1-12
   * @returns {Array} 黄道吉日数组，按吉凶评分排序
   * @throws {Error} 当年份或月份无效时抛出异常
   * 
   * 功能说明：
   * - 分析指定月份每一天的宜忌情况
   * - 基于宜事和忌事的数量及重要性评估吉凶
   * - 返回评分较高的黄道吉日
   * 
   * 评判标准：
   * - 宜事多于忌事
   * - 包含重要吉事（嫁娶、开业、搬家等）
   * - 按评分从高到低排序
   * 
   * 使用示例：
   * const auspiciousDays = lunarService.getAuspiciousDays(2024, 1);
   * console.log(auspiciousDays[0]); // 当月最佳吉日
   */
  getAuspiciousDays(year, month) {
    try {
      const auspiciousDays = [];
      const daysInMonth = new Date(year, month, 0).getDate();

      // 重要吉事列表 - 用于判断是否为黄道吉日的关键指标
      const importantYi = [
        "嫁娶", "开业", "搬家", "入宅", "开工", "动土", "出行",
        "祭祀", "祈福", "安床", "开市", "交易", "立券", "纳财"
      ];

      for (let day = 1; day <= daysInMonth; day++) {
        const solar = Solar.fromYmd(year, month, day);
        const lunar = solar.getLunar();

        // 获取当日宜忌
        const yi = lunar.getDayYi();
        const ji = lunar.getDayJi();

        // 判断是否包含重要吉事
        const hasImportantYi = yi.some((item) => importantYi.includes(item));
        
        // 计算吉凶评分：宜事数量 - 忌事数量 + 重要吉事加分
        const baseScore = yi.length - ji.length;
        const importantBonus = hasImportantYi ? 10 : 0;
        const finalScore = baseScore + importantBonus;

        // 筛选条件：评分大于0且包含重要吉事
        if (finalScore > 0 && hasImportantYi) {
          auspiciousDays.push({
            date: `${year}-${month.toString().padStart(2, "0")}-${day.toString().padStart(2, "0")}`,
            lunar: lunar.getDayInChinese(),           // 农历日期
            yi: yi.slice(0, 3),                      // 只显示前3个宜事
            ji: ji.slice(0, 3),                      // 只显示前3个忌事
            score: finalScore,                       // 吉凶评分
            ganZhi: lunar.getDayInGanZhi(),          // 日期干支
            chong: lunar.getDayChong(),              // 冲煞
            sha: lunar.getDaySha(),                  // 煞向
          });
        }
      }

      // 按评分从高到低排序
      return auspiciousDays.sort((a, b) => b.score - a.score);
    } catch (error) {
      throw new Error(`获取黄道吉日失败: ${error.message}`);
    }
  }

  /**
   * 获取生肖运势信息
   * Get zodiac fortune information
   * 
   * @param {string} shengXiao - 生肖名称，例如："鼠"、"牛"、"虎"等
   * @param {string} date - 日期字符串，格式：YYYY-MM-DD
   * @returns {object} 生肖运势对象，包含综合运势、爱情、事业、财运、健康等
   * @throws {Error} 当生肖名称无效或日期格式错误时抛出异常
   * 
   * 功能说明：
   * - 基于生肖五行属性和当日五行计算运势
   * - 使用五行相生相克理论进行运势分析
   * - 提供幸运数字、幸运颜色、幸运方位等建议
   * 
   * 五行相生：木生火，火生土，土生金，金生水，水生木
   * 五行相克：木克土，土克水，水克火，火克金，金克木
   * 
   * 使用示例：
   * const fortune = lunarService.getZodiacFortune("龙", "2024-01-15");
   * console.log(fortune.overall); // 综合运势评分
   */
  getZodiacFortune(shengXiao, date) {
    try {
      // 第一步：解析日期并创建农历对象
      const [yearStr, monthStr, dayStr] = date.split("-");
      const solar = Solar.fromYmd(
        parseInt(yearStr, 10),
        parseInt(monthStr, 10), 
        parseInt(dayStr, 10)
      );
      const lunar = solar.getLunar();

      // 第二步：获取当日五行属性
      const dayWuXing = this._getDayWuXing(lunar);

      // 第三步：获取生肖对应的五行属性
      const zodiacWuXing = this._getZodiacWuXing(shengXiao);
      if (!zodiacWuXing) {
        throw new Error(`无效的生肖名称: ${shengXiao}`);
      }

      // 第四步：基于五行关系计算运势
      const fortune = this.calculateElementFortune(zodiacWuXing, dayWuXing);

      return {
        shengXiao,                          // 生肖
        date,                               // 日期
        overall: fortune.overall,           // 综合运势
        love: fortune.love,                 // 爱情运势
        career: fortune.career,             // 事业运势
        wealth: fortune.wealth,             // 财运
        health: fortune.health,             // 健康运势
        luckyNumber: fortune.luckyNumber,   // 幸运数字
        luckyColor: fortune.luckyColor,     // 幸运颜色
        luckyDirection: fortune.luckyDirection, // 幸运方位
        advice: fortune.advice,             // 运势建议
      };
    } catch (error) {
      throw new Error(`获取生肖运势失败: ${error.message}`);
    }
  }

  /**
   * 基于五行关系计算运势
   * Calculate fortune based on Wu Xing (Five Elements) relationships
   * 
   * @param {string} zodiacElement - 生肖五行属性
   * @param {string} dayElement - 当日五行属性
   * @returns {object} 运势信息对象
   * 
   * 功能说明：
   * - 基于传统五行相生相克理论计算运势
   * - 五行相生关系提升运势，相克关系降低运势
   * - 生成综合运势及各项细分运势评分
   * 
   * 计算规则：
   * - 基础分数：50分
   * - 生肖五行生日五行：+20分
   * - 日五行生生肖五行：+30分
   * - 生肖五行克日五行：+10分
   * - 日五行克生肖五行：-10分
   * - 五行相同：+15分
   */
  calculateElementFortune(zodiacElement, dayElement) {
    // 五行相生关系表：木生火，火生土，土生金，金生水，水生木
    const shengRelation = {
      木: "火", 火: "土", 土: "金", 金: "水", 水: "木"
    };

    // 五行相克关系表：木克土，土克水，水克火，火克金，金克木
    const keRelation = {
      木: "土", 土: "水", 水: "火", 火: "金", 金: "木"
    };

    let score = 50; // 基础分数
    let advice = "";

    // 分析五行关系并调整分数
    if (zodiacElement === dayElement) {
      // 五行相同，运势平稳
      score += 15;
      advice = "今日五行与生肖相同，运势平稳，适合稳步发展。";
    } else if (shengRelation[zodiacElement] === dayElement) {
      // 生肖五行生日五行，运势较好
      score += 20;
      advice = "今日五行相生，运势较佳，适合主动出击，把握机会。";
    } else if (keRelation[zodiacElement] === dayElement) {
      // 生肖五行克日五行，运势一般但有主导权
      score += 10;
      advice = "今日你的五行克制环境，需要谨慎行事，但可以主导局面。";
    } else if (shengRelation[dayElement] === zodiacElement) {
      // 日五行生生肖五行，运势很好
      score += 30;
      advice = "今日得五行相助，运势极佳，是行动和决策的好时机。";
    } else if (keRelation[dayElement] === zodiacElement) {
      // 日五行克生肖五行，运势较差
      score -= 10;
      advice = "今日五行相冲，宜静不宜动，多加小心，避免冲突。";
    } else {
      // 五行平和
      advice = "今日五行平和，按部就班即可，保持现状。";
    }

    // 确保分数在合理范围内
    const finalScore = Math.min(100, Math.max(0, score));

    // 生成各项运势（在基础分数上增加随机波动）
    return {
      overall: finalScore,
      love: Math.min(100, Math.max(0, finalScore + (Math.random() - 0.5) * 20)),
      career: Math.min(100, Math.max(0, finalScore + (Math.random() - 0.5) * 20)),
      wealth: Math.min(100, Math.max(0, finalScore + (Math.random() - 0.5) * 20)),
      health: Math.min(100, Math.max(0, finalScore + (Math.random() - 0.5) * 20)),
      luckyNumber: [
        Math.floor(Math.random() * 9) + 1,
        Math.floor(Math.random() * 9) + 1,
      ],
      luckyColor: this.getLuckyColor(zodiacElement),
      luckyDirection: this.getLuckyDirection(zodiacElement),
      advice,
    };
  }

  /**
   * 获取幸运颜色
   * Get lucky color based on element
   * 
   * @param {string} element - 五行属性
   * @returns {Array} 幸运颜色数组
   */
  getLuckyColor(element) {
    const colors = {
      木: ["绿色", "青色"],
      火: ["红色", "橙色"],
      土: ["黄色", "棕色"],
      金: ["白色", "银色"],
      水: ["黑色", "蓝色"],
    };
    return colors[element] || ["金色"];
  }

  /**
   * 获取幸运方位
   * Get lucky direction based on element
   * 
   * @param {string} element - 五行属性
   * @returns {string} 幸运方位
   */
  getLuckyDirection(element) {
    const directions = {
      木: "东方",
      火: "南方", 
      土: "中央",
      金: "西方",
      水: "北方",
    };
    return directions[element] || "东南";
  }

  /**
   * 获取节气信息
   * Get solar terms information
   * 
   * @param {number} year - 年份
   * @returns {Array} 节气列表，包含全年24个节气的详细信息
   */
  getSolarTerms(year) {
    const solarTerms = [];

    for (let month = 1; month <= 12; month++) {
      const solar = Solar.fromYmd(year, month, 1);
      const lunar = solar.getLunar();

      // 获取当月的节气
      const jieQi = lunar.getJieQi();
      if (jieQi) {
        solarTerms.push({
          name: jieQi,
          date: solar.toYmd(),
          month: month,
          description: this.getSolarTermDescription(jieQi),
        });
      }
    }

    return solarTerms;
  }

  /**
   * 获取节气描述
   * Get solar term description
   * 
   * @param {string} jieQi - 节气名称
   * @returns {string} 节气描述
   */
  getSolarTermDescription(jieQi) {
    const descriptions = {
      立春: "春季开始，万物复苏，阳气上升",
      雨水: "降雨增多，气温回升，冰雪融化",
      惊蛰: "春雷响动，蛰虫苏醒，大地回春",
      春分: "昼夜平分，春意盎然，播种时节",
      清明: "天清地明，踏青扫墓，万物生长",
      谷雨: "雨水充沛，谷物生长，春耕结束",
      立夏: "夏季开始，气温升高，万物繁茂",
      小满: "麦类作物籽粒饱满，夏熟作物生长旺盛",
      芒种: "有芒作物成熟收割，夏种开始",
      夏至: "白昼最长，暑热将至，阳气最盛",
      小暑: "天气炎热，但未到极点，暑气渐盛",
      大暑: "一年中最热的时期，酷暑难耐",
      立秋: "秋季开始，暑去凉来，收获在望",
      处暑: "暑热结束，秋高气爽，昼夜温差大",
      白露: "露水增多，秋意渐浓，天气转凉",
      秋分: "昼夜平分，秋收时节，硕果累累",
      寒露: "露水更凉，深秋来临，准备过冬",
      霜降: "开始降霜，准备过冬，万物萧瑟",
      立冬: "冬季开始，万物收藏，进入冬眠",
      小雪: "开始降雪，气温下降，天地肃杀",
      大雪: "雪量增大，严寒将至，万物蛰伏",
      冬至: "白昼最短，数九寒天，阴气最盛",
    };

    return descriptions[jieQi] || "节气时令，顺应自然";
  }

  // ============私有辅助方法开始===========
  
  /**
   * 获取当日五行属性
   * @private
   */
  _getDayWuXing(lunar) {
    const dayGan = lunar.getDayGan();
    const wuXingMap = {
      甲: "木", 乙: "木",
      丙: "火", 丁: "火", 
      戊: "土", 己: "土",
      庚: "金", 辛: "金",
      壬: "水", 癸: "水"
    };
    return wuXingMap[dayGan] || "土";
  }

  /**
   * 获取生肖对应的五行属性
   * @private
   */
  _getZodiacWuXing(shengXiao) {
    const zodiacWuXing = {
      鼠: "水", 牛: "土", 虎: "木", 兔: "木",
      龙: "土", 蛇: "火", 马: "火", 羊: "土",
      猴: "金", 鸡: "金", 狗: "土", 猪: "水",
    };
    return zodiacWuXing[shengXiao];
  }

  /**
   * 获取时辰干支
   * @private
   */
  _getTimeGanZhi(lunar, timeIndex) {
    const timeZhi = ["子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"];
    return timeZhi[timeIndex] + "时";
  }

  /**
   * 计算时辰宜忌
   * @private
   */
  _calculateTimeYiJi(lunar, time) {
    // 基于时辰和日期计算宜忌（简化版本）
    return {
      yi: ["祈福", "祭祀"],
      ji: ["出行", "动土"],
      chong: "冲煞方位"
    };
  }

  /**
   * 获取九星信息
   * @private
   */
  _getJiuXing(lunar) {
    return "九星飞宫信息";
  }

  /**
   * 获取胎神信息
   * @private
   */
  _getTaiShen(lunar) {
    return "胎神占方信息";
  }
}

// 导出单例对象
export default new LunarService();
